package org.dromara.system.kernel.channel;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.system.domain.PayAccount;
import org.dromara.system.domain.PayGroupAccount;
import org.dromara.system.domain.PayOrder;
import org.dromara.system.domain.PayOrderLog;
import org.dromara.system.domain.bo.OrderRelateBo;
import org.dromara.system.domain.bo.aparams.AOrderBo;
import org.dromara.system.domain.bo.cparams.OrderProduct;
import org.dromara.system.domain.bo.cparams.OrderUpdateBo;
import org.dromara.system.domain.bo.companychannel999.CompanyChannel999Bo;
import org.dromara.system.kernel.OrderUpdateKernel;
import org.dromara.system.service.IPayAccountService;
import org.dromara.system.service.IPayOrderLogService;
import org.dromara.system.service.IPayOrderService;
import org.dromara.system.utils.ConversionUtils;
import org.dromara.system.utils.RequestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.util.*;

@RefreshScope
@RequiredArgsConstructor
@Service
public class CompanyChannel999Kernel {

    private final IPayOrderLogService orderLogService;
    private final IPayOrderService orderService;
    private final IPayOrderService payOrderService;
    private final OrderUpdateKernel orderUpdateKernel;
    private final IPayAccountService accountService;
    @Value("${gatewayDomain}")
    public String gatewayDomain;

    /**
     * 获取支付链接
     *
     * @param relateBo 订单关联信息
     */
    public R<PayOrder> requestPayLink(OrderRelateBo relateBo) {

        PayAccount account = relateBo.getAccount();
        PayGroupAccount groupAccount = relateBo.getGroupAccount();
        PayOrder order = relateBo.getOrder();
        PayOrderLog log = relateBo.getLog();

        //获取账号请求域名
        String domain = account.getDomain();
        if (StringUtils.isEmpty(domain)) {
            return R.fail("DomainUrl is invalid", order);
        }

        //获取账号配置
        JSONObject config = account.getAccountConfig();
        if (!config.containsKey("clientId") || !config.containsKey("secretKey")) {
            return R.fail("Account Config is invalid", order);
        }
        Integer clientId = config.getInteger("clientId"); //商户ID
        String secretKey = config.getString("secretKey"); //商户密匙

        //构建参数
        JSONObject params = buildParams(groupAccount, order, clientId, secretKey);
        if (params == null) {
            return R.fail("no config params found", order);
        }

        //请求
        long time = System.currentTimeMillis();
        String res1;
        try {
            res1 = new RequestUtils().doPostJsonNoTry(domain + "/api/gateway/uni_pay", params.toJSONString(JSONWriter.Feature.WriteMapNullValue));
        } catch (Exception e) {
            res1 = "请求失败：" + e.getMessage();
        }

        //记录请求日志
        orderLogService.saveLog(log.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "获取支付链接", params.toString(JSONWriter.Feature.WriteMapNullValue), res1, System.currentTimeMillis() - time);

        try {
            if (StringUtils.isEmpty(res1) || res1.startsWith("请求失败")) {
                return R.fail("Request link null", order);
            }

            //解析返回参数
            JSONObject result;
            try {
                result = JSONObject.parseObject(res1);
            } catch (Exception e) {
                return R.fail(res1, order);
            }

            if (!Objects.equals(result.getInteger("code"), 200)) {
                return R.fail(result.getString("msg"), order);
            }

            String payUrl = result.getString("content");

            //写到订单对象里，返出去使用
            order.setLink(payUrl);

            //更新订单
            PayOrder up = new PayOrder();
            up.setOrderId(order.getOrderId());
            up.setLink(payUrl);
            orderService.updatePayOrderAsync(up);

            //记录更新日志
            orderLogService.saveLog(log.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新B端订单信息", JSONObject.toJSONString(up), "success", 10L);

            return R.ok(order);

        } catch (Exception e) {
            return R.fail("Request link fail", order);
        }
    }

    /**
     * 更新订单
     *
     * @param json 参数
     * @return JSONObject
     */
    public R<?> updateOrder(JSONObject json) {
        System.out.println("updateCpCh999支付回调：" + json.toJSONString());
        String merchant_id = json.getString("merchant_id");
        String token = json.getString("token");
        String status = json.getString("status");
        String order_id = json.getString("order_number");
        String trade_no = json.getString("trade_no");
        String sign = json.getString("sign");
        if (StringUtils.isEmpty(merchant_id) || StringUtils.isEmpty(token) || StringUtils.isEmpty(status) || StringUtils.isEmpty(order_id) || StringUtils.isEmpty(trade_no) || StringUtils.isEmpty(sign)) {
            return R.fail("params is valid");
        }

        Long orderId = Long.parseLong(order_id.split("_")[0]);

        PayOrder order = payOrderService.selectById(orderId);
        if (order == null) {
            return R.fail("Order does not exist");
        }
        if (Objects.equals(status, "pending")) {
            return R.ok();//等待支付
        }

        //获取账号配置
        PayAccount account = accountService.selectById(order.getAccountId());
        if (account != null) {
            //获取账号配置
            JSONObject config = account.getAccountConfig();
            if (config.containsKey("clientId")) {
                String secretKey = config.getString("secretKey"); //商户密匙
                //merchant_id|order_number|trade_no|secret_key
                String si = EncryptUtils.encryptByMd5(merchant_id + "|" + order_id + "|" + trade_no + "|" + secretKey);
                if (!Objects.equals(si.toUpperCase(Locale.ROOT), sign)) {
                    return R.fail("sign is invalid");
                }
            }
        }

        //更新订单参数
        OrderUpdateBo bo = new OrderUpdateBo(orderId, Objects.equals(status, "completed") ? 2 : 3, null);

        //更新订单
        return orderUpdateKernel.updateOrder(order, bo, json.toJSONString());
    }

    /**
     * 构建请求参数
     *
     * @param order 订单
     * @return JSONObject
     */
    private JSONObject buildParams(PayGroupAccount groupAccount, PayOrder order, Integer clientId, String secretKey) {

        String currency; //币别
        BigDecimal amount; //金额
        if (Objects.equals(groupAccount.getIsForce(), 1) && order.getForceCurrency() != null) {
            currency = order.getForceCurrency();
            amount = order.getForceMoney();
        } else {
            currency = order.getCurrency();
            amount = order.getCMoney();
        }

        amount = amount.setScale(2, RoundingMode.HALF_UP);

        AOrderBo.Address bill = JSONObject.parseObject(order.getCustomer(), AOrderBo.Address.class);
        AOrderBo.Address shipping = JSONObject.parseObject(order.getShipping(), AOrderBo.Address.class);

        //订单信息
        CompanyChannel999Bo bo = new CompanyChannel999Bo();
        bo.setMerchant_id(clientId);
        bo.setStore_id(order.getAppId().intValue());
        bo.setOrder_number(order.getOrderId() + "_" + ConversionUtils.generateShortCode(order.getOrderId() + "", 14));
        bo.setDomain(gatewayDomain);
        bo.setShipping_price("0");
        bo.setTax_price("0");
        bo.setDiscount_price("0");
        bo.setOther_price("0");
        bo.setTotal_price(amount.toPlainString());
        bo.setCurrency(currency);
        bo.setTimestamp(Instant.now().getEpochSecond());
        bo.setPayment_method("3party");
        bo.setDefault_lang("en");
        bo.setNotice_url(gatewayDomain + "/api/system/external/updateCpCh999");
        bo.setSuccess_url(order.getSuccessUrl());
        bo.setReturn_url(order.getFailureUrl());
        bo.setNote("");
        bo.setBilling_first_name(bill.getFirstName());
        bo.setBilling_last_name(bill.getLastName());
        bo.setBilling_company("");
        bo.setBilling_address1(bill.getAddress1());
        bo.setBilling_address2(bill.getAddress2());
        bo.setBilling_city(bill.getCity());
        bo.setBilling_state(bill.getState());
        bo.setBilling_country(bill.getCountry());
        bo.setBilling_postcode(bill.getPostcode());
        bo.setBilling_email(bill.getEmail());
        bo.setBilling_phone(bill.getPhone());
        bo.setShipping_first_name(shipping.getFirstName());
        bo.setShipping_last_name(shipping.getLastName());
        bo.setShipping_company("");
        bo.setShipping_address1(shipping.getAddress1());
        bo.setShipping_address2(shipping.getAddress2());
        bo.setShipping_city(shipping.getCity());
        bo.setShipping_state(shipping.getState());
        bo.setShipping_country(shipping.getCountry());
        bo.setShipping_postcode(shipping.getPostcode());
        bo.setShipping_phone(shipping.getPhone());

        //产品信息
        List<CompanyChannel999Bo.Product> prods = new ArrayList<>();
        List<OrderProduct> products = JSONArray.parseArray(order.getProduct(), OrderProduct.class);
        for (OrderProduct product : products) {
            CompanyChannel999Bo.Product obj = new CompanyChannel999Bo.Product();
            obj.setId(StringUtils.isNotBlank(product.getPostId()) ? product.getPostId() : new Random().nextInt(100000000) + "");
            obj.setTitle(product.getName());
            obj.setImage_url(product.getImage());
            obj.setSku("SKU" + product.getPostId());
            obj.setPrice(product.getPrice().toPlainString());
            obj.setQuantity(product.getQuantity());
            prods.add(obj);
        }
        bo.setProducts(prods);

        // 构建签名
        String sign = EncryptUtils.encryptByMd5(clientId + "|" + bo.getOrder_number() + "|" + bo.getTotal_price() + "|" + bo.getCurrency() + "|" + bo.getTimestamp() + "|" + secretKey);
        bo.setSign(sign.toUpperCase(Locale.ROOT));

        return JSONObject.from(bo, JSONWriter.Feature.WriteMapNullValue);
    }

}
